# @arthor quoc.le
#! C:/Perl/bin/perl -w
use strict;
use warnings;
#use diagnostics;
use Data::Dumper;
package Juniper;
sub new
{
    my $class = shift;
    my $self = {
        _fileName => shift,
        _variable => shift,
        _paramsDefault =>shift,
        _testCase  => shift,
        _topology  => shift,
        _routerConfig  => shift,
        _allRouter => shift,
        _connections =>shift
    };

    bless $self, $class;
    return $self;
}
# Getter & Setter

# File Name
sub setFileName {
    my ( $self, $fileName ) = @_;
    $self->{_fileName} = $fileName if defined($fileName);
    return $self->{_fileName};
}

sub getFileName {
    my( $self ) = @_;
    return $self->{_fileName};
}

# Variable
sub setVariable {
    my ( $self, $variable ) = @_;
    $self->{_variable} = $variable if defined($variable);
    return $self->{_variable};
}

sub getVariable {
    my( $self ) = @_;
    # return $self->{_variable};
    # quoc.le
    my %values; # Hold all values
    my $val = $self->{_variable};
    my @vals = split(';',$val);
    for my $item (@vals)
    {
        # print $item;
        if($item =~ m/\"/)
        { 
             my @items = split('\"',$item);
             # print $items[0]," ", $items[1];
             my @its = split(' ',$items[0]);
             $values{$its[0]} = $items[1];
             # print "\nvalues1 ",$its[0]," ",$items[1],"\n";
        }else
        {
            my @items2 = split(/\s+/,$item);
            if(scalar @items2 > 2){
            $values{$items2[1]} = $items2[2];
            }
            # print "\nvalues2 ",$items2[1]," ",$items2[2],"\n";
        }
    }
    return %values;
}
# Param Default
sub setParamsDefault {
    my ( $self, $paramsDefault ) = @_;
    $self->{_paramsDefault} = $paramsDefault if defined($paramsDefault);
    return $self->{_paramsDefault};
}

sub getParamsDefault {
    my( $self ) = @_;
    return $self->{_paramsDefault};
}

# nghi.phan
# Create a hash of params default 
sub getHashParamsDefault {
    my( $self ) = @_;
    (my $tempParams = $self->{_paramsDefault}) =~ s/params-default(.*)\{//;
    my @secondaryParams = split('}', $tempParams);
    my @paramsArr;
    my %params_default = ();
    my $key;
    my $value;
    my $s;
    for $s (@secondaryParams)
    {
            @paramsArr = split('{', $s);
            $key = regex_or($paramsArr[0]);
            $value = regex_or($paramsArr[1]);
            
            if (($key ne "") && ($value ne "")) {
                $params_default{"params-default"}{$key} = $value;
            }
    }
    return %params_default;
}

# TestCase
sub setTestCase {
    my ( $self, $testCase ) = @_;
    $self->{_testCase} = $testCase if defined($testCase);
    return $self->{_testCase};
}

sub getTestCase {
    my( $self ) = @_;
    return $self->{_testCase};
}
sub getArrTestCase
{
        # my( $self ) = @_; 
	my %test_case;
	my @aoh;
	my $valTC =shift->getTestCase();
	my @valsTC = split(';',$valTC);
	for my $itemTC (@valsTC)
	{
                my %hsh = ();
                my ($keyt, $valt);
		# print $itemTC,"\nEND\n";
		$itemTC = regex_or($itemTC);
		my $name = substr ($itemTC,0,15);
		if(length($itemTC) > 15)
		{
			$itemTC = substr ($itemTC,15);
			# add test case to hash
			$test_case{$name} = $itemTC;
			# print $name,"\n";
			# print "item: ",$itemTC,"\n";
			my @all_val_key = split('\n',$itemTC);
			for my $ct (@all_val_key)
			{
			    # print "item : ",$ct,"\n";
			   
			    if( $ct =~ m/\"/)
			    {
			        my @t = split('"',$ct);
			        if($t[1] =~ m/x-/)
			        {
			            $keyt = $t[1];
			            # print "$keyt\n";
			        }
			        if(length(regex_or($t[2])) > 0 )
			        {
			            $valt = regex_or($t[2]);
			            # print "$valt\n";
                                }else{
                                    $valt =  regex_or($t[3]);  
                                    # print "$valt\n";
                                }
                            }
                            if($keyt)
                            {
                                $hsh{$keyt} = $valt;
                            }
                        }
                        
		}
		push (@aoh , %hsh);
	}	
	# hash
	# key : x-testcase-xxx
	# values : string
	return @aoh;
}
sub getDetailTestCases
{
    # get valuse of test case
    # param : name of test case : x-testcase-xxx
    # return : hash of all variable
    my @keys = @_;
    print $keys[1],"\n";
    my %all_test_case = shift->getArrTestCase(); 
    print keys %all_test_case;
    my $var12 =  $all_test_case{$keys[1]};
}
# Topology
sub setTopology {
    my ( $self, $topology ) = @_;
    $self->_topology = $topology if defined($topology);
    return $self->{_topology};
}

sub getTopology {
    my( $self ) = @_;
    return $self->{_topology};
}

# Router Config
sub setRouterConfig {
    my ( $self, $routerConfig ) = @_;
    $self->{_routerConfig} = $routerConfig if defined($routerConfig);
    return $self->_routerConfig;
}

sub getRouterConfig {
    my( $self ) = @_;
    return $self->{_routerConfig};
}
sub router2hash
{
    my %router_connect;
    my( $self ) = @_;
    my $router = $self->{_routerConfig};
    my @routes = split('endR',$router);
    for my $rou (@routes)
    {
        my ($key1, $key2 , $val2 );
        $rou = regex_or($rou);
        if($rou && $rou !~ m/h0/)
        {
            # print "rou: ",$rou,"\n";
            my @intf = split('interfaces',$rou);
            my @getk = split('{',$intf[0]);
            $key1 = $getk[0];
            my @getcn ;
            if($intf[1])
            {
                @getcn = split('}',$intf[1]);
            }
            for my $item (@getcn)
            {
                my $count = countChar('{',$item);
                my @kv2 = split('{',$item);
                if($count ==2)
                {
                    $key2 = $kv2[1];
                    $val2 = $kv2[2];
                }elsif($count == 1 )
                {
                    $key2 = $kv2[0];
                    $val2 = $kv2[1];
                }
            # if key same rx-y or alonez -> key = rx
            if($key2){
                if(($key2 =~ m/lone/ || countChar('r',$key2) == 1) && $key2 !~ m/ress/)
                {
                    $key1 = regex_or($key1);
                    $key2 = $key1;
                }
            }
            # add hash here
                if($key2)
                {
                    $router_connect{$key1}{$key2}= $val2;
                }
            }
            # print @getcn;
        }
    }
    return %router_connect;
}
# get all router exist
sub get_arr_router
{
    my %hash_connect = shift->router2hash();
    my @all_router;
    foreach my $k1 ( sort keys %hash_connect ) {
        push(@all_router,$k1);
    }
    return @all_router;
}
# get all connect from interface and return array
sub get_arr_connect_from_hash
{
    my %hash_connect = shift->router2hash();
    my @all_connect;
    foreach my $k1 ( sort keys %hash_connect ) {
      foreach my $k2 ( sort keys %{$hash_connect{$k1}} ) {
        push(@all_connect,$k2);
      }
    }
    return @all_connect;
}
# read array connect, add to hash and count connect   'r0-r1'=>3 , 'r1-rt0'=>4 ....
sub count_all_connect
{
    my %connect;
    my ($self) = @_;
    my @all_routers = $self->get_arr_router();
    my @all_routes_tmp = @all_routers;
    # print @all_routers,"\n";
    my @all_connects = $self->get_arr_connect_from_hash();
    # print @all_connects;
    while(@all_routers)
    {
        my $item = pop @all_routers;
        $item = regex_or($item);
        # print "pop: ",$item,"\n";
        # print "all: ",@all_routers;
        for my $item2 (@all_routers)
        {
            $item2 = regex_or($item2);
            # print $item."-".$item2,"\n";
            my @cr_key = sort $item, $item2;
            my $key = $cr_key[1]."-".$cr_key[0];
            if($cr_key[1] =~ $cr_key[0])
            {
                next;
            }
            my $val = 0;
            my $vargr = 0;
            for my $item3 (@all_connects)
            {
                $item3 = regex_or($item3);
                if(length($item3) == 1 && scalar @all_routes_tmp == 2)
                {
                    @all_routes_tmp = sort @all_routes_tmp;
                    $key = regex_or($all_routes_tmp[1])."-".regex_or($all_routes_tmp[0]);
                    $val++;
                }
                elsif($item3 =~ m/$item/ && $item3 =~ m/$item2/)
                {
                    $val++;
                }elsif($item3 =~ m/link/ && scalar @all_routes_tmp == 2)
                {
                    @all_routes_tmp = sort @all_routes_tmp;
                    $key = regex_or($all_routes_tmp[1])."-".regex_or($all_routes_tmp[0]);#."link";
                    # print "Exception: ",$item3,"\n";
                    # print @all_routes_tmp;
                    $val++;
                }
                # elsif($item3 =~ m/gr/ && $item3 =~ m/$item2/)
                # {
                    # print "item 2 : $item2\n";
                    # my @groud = sort 'gr',$item2;
                    # $key = regex_or($groud[1])."-".regex_or($groud[0]);
                    # $vargr++;
                    # print "ground",$item3," and val : $val","\n";
                # }
            }
            
            # if($key =~ m/gr/)
            # {
                # print "key : $key and val: $vargr\n";
                # # $connect{$key} = $vargr;
            # }
                if($val > 1)
                {
                    if($val %2 == 0)
                    {
                        $val = $val/2;
                    }else
                    {
                        $val = 1 + int($val/2);
                    }
                }
                $connect{$key} = $val;     
        }# for @all_router
    }#while

    # print "size of hash:  " . keys( %connect ) . ".\n";
    my $king = 0;
    for my $abc (keys %connect)
    {
        $king = $king + $connect{$abc};
    }
    $king = $king * 2;
    # print "Total values of hash ".$king."\n";
    # print "Size of all connect : ",scalar @all_connects,"\n";
    if(scalar @all_connects - $king > 0)
    {
        # print $self->{_fileName},"\n";
        # print "size of hash:  " . keys( %connect ) . ".\n";
        # print "Total values of hash ".$king."\n";
        # print "Size of all connect : ",scalar @all_connects,"\n";
        # print "all connect : ",@all_connects,"\n";
        # print "all router : ",@all_routes_tmp,"\n";
        # print "hash of connect ",%connect,"\n\n";
        for my $grd (@all_connects)
        {
            if($grd)
            {
                if($grd =~ m/gr/)
                {
                    if($grd =~ m/\_/)
                    {
                        $grd =~ s/\_/\-/; # miss when r1gr
                    }
                    my @gs = split("-",$grd);
                    if(scalar @gs > 0)
                    {
                        @gs = sort @gs;
                        if($gs[0] && $gs[1])
                        {
                            my $keygr = regex_or($gs[1])."-".regex_or($gs[0]);
                            $connect{$keygr} = 1; # only one gr for each router
                        }
                    }    
                }
            }
        }
    }
        
    # case lone and rx-y
    my @all_routers1 = $self->get_arr_router();
    my @all_connects1 = $self->get_arr_connect_from_hash();
    
    for my $rx (@all_routers1)
    {
        my $kx = $rx;
        my $vx = 0;
        for my $cx (@all_connects1)
        {
            if(length($cx) < 4 && countChar('r',$rx) == 1)
            {
                $vx++;
            }
        }
        $connect{$kx} = $vx;
    }
    return %connect;
}
# All Router
sub setAllRouter {
    my ( $self, $allRouter ) = @_;
    $self->{_allRouter} = $allRouter if defined($allRouter);
    return $self->{_allRouter};
}

sub getAllRouter {
    my ( $self ) = @_;
    return $self->{_allRouter};
}

# Connection
sub setConnect {
    my ( $self, $connect ) = @_;
    $self->{_connections} = $connect if defined($connect);
    return $self->{_connections};
}

sub getConnect {
    my( $self ) = @_;
    return $self->{_connections};
}
# return hash {r0-rt0|=>2 ...  not use , replace by count_all_connect
sub allConnect
{
    my @allcn;
    my $conn = shift->getConnect();
    my @conns;
    @conns = split(';',$conn);
    for my $t (@conns)
    {
        if($t =~ m/link/)
        {
            push(@allcn,$t);
        }
        if($t =~ m/_/)
        {
            $t =~ s/_/-/;
        }
        my @ts = split('-',$t);
        my $rl;
        if(scalar @ts > 1)
        {
            @ts = sort ($ts[0], $ts[1]);
            $rl = $ts[1]."-".$ts[0];
        }
        # print " $rl \n";
        push(@allcn,$rl);
    }
    
    # travel @allcn and store to hash
    my %all_connect = ();
    my $num = 0;
    for my $item_r (@allcn)
    {
        if($item_r && $item_r !~ m/link/)
        {
            my $item_reserve = reserve_router($item_r);
            if (exists $all_connect{$item_r} || exists $all_connect{$item_reserve}) # r0-rt0 && rt0-r0
            {
                    # print "Existed! \n";
                    if (exists $all_connect{$item_r})
                    {
                        $num = $all_connect{$item_r};
                        $num++;
                        # print $num,"\n";
                        $all_connect{$item_r} = $num;
                    }
                    elsif(exists $all_connect{$item_reserve})
                    {
                        $num = $all_connect{$item_reserve};
                        $num++;
                        # print $num,"\n";
                        $all_connect{$item_reserve} = $num;
                    }

            }else
            {  
                    $all_connect{$item_r} = 1;
            }
        }elsif($item_r && $item_r =~ m/link/)
        {
             if (exists $all_connect{'link'})
                    {
                        $num = $all_connect{'link'};
                        $num++;
                        # print $num,"\n";
                        $all_connect{'link'} = $num;
                    }
            else{
                $all_connect{'link'} = 1;
            }
        }
    }
    my @allkeys = keys %all_connect;
    # print @allkeys;
    for my $ks (@allkeys)
    {
        if($all_connect{$ks} %2 == 0)
        {
            $all_connect{$ks} = $all_connect{$ks} /2;
        }else
        {
            if($all_connect{$ks} > 1 )
            {
                $all_connect{$ks} = 1+ int($all_connect{$ks} /2);
            }
        }
    }
    return %all_connect;
    
}
# Show all data
sub showAll
{
    my( $self ) = @_;
    print $self->{_fileName},"\n";
    print $self->{_variable},"\n";
    print $self->{_testCase},"\n";
    print $self->{_topology},"\n";
    print $self->{_routerConfig},"\n";

}
sub addQuotes() { 
    my $string = shift;
    return "\"" + $string + "\""; 
} 
sub regex_or {
  my $string = shift;
  $string =~ s/(?:^\s+)||(?: +$)//g;
  return $string;
}
sub reserve_router
{
    my $router = shift;
    my @rous = split("-", $router);
    my $out ='';
    if(my $sizer = @rous > 1)
    {
        $out = join("-", reverse $rous[0], $rous[1]); 
    }
    # print $out,"\n\n";
    return $out;
}


# Return a block of keyword {}  &readBlock(string_which_content_block,"keyword")
sub readBlock
{
    my $config = shift;
    my $blockName = shift;
    my @arrayConfig = split("\n",$config);
    my $i;
    my $block;
    my @arrBlock;
    my $open = 0;
    my $close = 0;
    my $size = @arrayConfig;
    for($i=0;$i<$size;$i++)
    {
        if($arrayConfig[$i] =~ m/^$blockName/)
        {
            $block ='';
            $block = $block."$arrayConfig[$i]\n";
            $open = $open + countChar("{",$arrayConfig[$i]);
            $close = $close + countChar("}",$arrayConfig[$i]);
            if($open == $close && $open != 0)
            {
                next;
            }
            while($open > $close)
            {
                $i++;
                $open = $open + countChar("{",$arrayConfig[$i]);
                $close = $close + countChar("}",$arrayConfig[$i]);
                $block = $block."$arrayConfig[$i]\n";
            } 
            # read a block
            push(@arrBlock,$block);
        }
    }   
    return @arrBlock;
}


# count char 
sub countChar()
{
    my $char = shift;
    my $string = shift;
    my @count = $string =~ /$char/g;
    return scalar @count;
}


#
sub connectDetail
{
    my( $self ) = @_;
    my @arrConnect = split(/;/,$self->{_connections});
    my %connectDetail;
    #check connect
    if(scalar @arrConnect == 0)
    {
        print "have not connection\n";
        return;
    }
    else
    {
        my $config = $self->{_routerConfig};
        my @detail;
        foreach my $connect (@arrConnect)
        {
            @detail = &readBlock($config,$connect);
        }
        $connectDetail{@detail} = [@detail];
    }
    return %connectDetail;
}


# Get hash of connection detail



sub change_link_to_connect
{
    # my $input = shift;
    my( $self ) = @_;
    print $self->{_allRouter};
    # print $all_router;
    # return $input;
}
1;

